parser grammar AnalexParser;

options {
  backtrack = true;  
  language = Java;
  tokenVocab = AnalexLexer;
}

@header {
  package Practica7.ParserYacc;
}

@members {
  private int bloque = 0;
  public int get_bloque(){
    return bloque;
  }
  private ArrayList<String> errors = new ArrayList<String>();
  public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
    String hdr = getErrorHeader(e);
    String msg = getErrorMessage(e, tokenNames);
    errors.add(hdr + " " + msg);
  }
   
  public ArrayList<String> getErrors() {
    return errors;
  }
}

input: ( instructions ) EOF;

instructions: (declarations)* SECTIONSEPARATOR (rules)+ (SECTIONSEPARATOR (programs)*)?;

bloqueC: (programs)*;
// Declaración
declarations
      : globaldefinition
      | definitionyacc  {System.out.println ("Entra en declarations");};
      
globaldefinition
      : LEFTGLOBALDEFINITION 
          (includelibrary|typedef|declarationc|define|functiondefinition)+ 
        RIGHTGLOBALDEFINITION {System.out.println ("Entra en glogaldefinition");};
      
definitionyacc
      : start
      | union
      | token
      | type
      | left  {System.out.println ("Entra en definitionYACC");};

      
includelibrary
      : INCLUDE LIBRARY {System.out.println ("Entra en includelibrary");};
      
typedef
  : TYPEDEF STRUCT ID 
    LEFTBRACE 
      (declarationc)+ 
    RIGHTBRACE ID SEPARATOR {System.out.println ("Entra en typedef");};
    
declareonebyone
      : (typesc|ID) (MULT)? (ID|ARRAY)  {System.out.println ("Entra en declareonebyone");}; 
object
  : ((ID (functionheader)?)|ARRAY)  {System.out.println ("Entra en object");};
  
functionheader
      : LEFTPAREN 
          (declareonebyone (COMMA declareonebyone)*)? 
        RIGHTPAREN  {System.out.println ("Entra en functionheader");};
        
functiondefinition
      : (typesc|ID) ID functionheader (COMMA ID functionheader)* SEPARATOR  {System.out.println ("Entra en functiondefinition");}; 
  

define
  : DEFINE ID (NUMBER|ID|typesc)  {System.out.println ("Entra en define");};
start
  : START ID  {System.out.println ("Entra en start");};
union
  :   UNION 
      LEFTBRACE 
        (declarationc)+ 
      RIGHTBRACE  {System.out.println ("Entra en union");};
token
  : TOKEN (TAG)? (ID)+  {System.out.println ("Entra en token");};
type
  : TYPE (TAG)? ID  {System.out.println ("Entra en type");};
left
  : LEFT (LITERAL|ID)+  {System.out.println ("Entra en left");};

// --------------------------------------------------------------------------------------------------------------------- //

 
// Reglas
rules
  : ID DEFINITIONOFRULE rule (OR rule)* SEPARATOR {System.out.println ("Entra en rules");}; 
rule
  : (ID|LITERAL|PRECEDENCE)* (actions)? {System.out.println ("Entra en rule");};
actions
  : LEFTBRACE 
      (action)+ 
    RIGHTBRACE  {System.out.println ("Entra en actions");};
action
  : declarationc
  |((allocation|functioncall) SEPARATOR)
  |ifblock
  |whileloop
  |forloop  {System.out.println ("Entra en action");};

// --------------------------------------------------------------------------------------------------------------------- //


// Programs
programs
    : functionc
    | functionyacc
    | define  
    | block {System.out.println ("Entra en programs");};

functionc
    : (typesc|ID)? ID functionheader block  {System.out.println ("Entra en functionC");};
    
functionyacc
    : (ID)? functioncall (declarationc)+ block  {System.out.println ("Entra en functionYACC");};


// Parte común
declarationc
      : (typesc|ID) allocation (COMMA allocation)* SEPARATOR  {System.out.println ("Entra en declarationc");};

allocation
      : variable (OPERATOR (exp))*  {System.out.println ("Entra en allocation");};

variable
    : (MULT)? (ID|ARRAY|PSEUDOVARIABLE|addorsubtoid)  {System.out.println ("Entra en variable");};
    
exp
  : (MINUS)? exp_add ((PLUS|MINUS) exp_add)*  {System.out.println ("Entra en exp");};

exp_add
  : exp_base ((MULT|DIV) exp_base)* {System.out.println ("Entra en exp_add");};

exp_base
    : variable
    | functioncall
    | addorsubtoid
    | NUMBER
    | STRING
    | LITERAL
    | (PARENTESIS_IZQ exp PARENTESIS_DER) {System.out.println ("Entra en exp_base");};

addorsubtoid
      : ((ADDONE|SUBONE) ID)|(ID (ADDONE|SUBONE));

functioncall
      : ID functioncallparams {System.out.println ("Entra en functioncall");};

functioncallparams
      : (LEFTPAREN (exp (COMMA exp)*)? RIGHTPAREN);

specialfunctioncall
      : (BREAK|RETURN|CONTINUE|YYERROR) ((functioncallparams)? | (exp)?) SEPARATOR;

typesc
  : DOUBLE
  | INT
  | CHAR  {System.out.println ("Entra en typesc");};

// Bucles e if
whileloop: WHILE 
      LEFTPAREN 
        //condition (LOGICOPERATOR condition)*
        LEFTPAREN 
          allocation
        RIGHTPAREN
        CONDITION exp 
      RIGHTPAREN (block|sentence) {System.out.println ("Entra en whileloop");}; 
ifblock: IF 
      LEFTPAREN 
        condition (LOGICOPERATOR condition)* 
      RIGHTPAREN (block|sentence) 
    (ELSE (block|sentence))?  {System.out.println ("Entra en ifblock");};
forloop: FOR 
      LEFTPAREN 
        (declarationc)? (SEPARATOR)? condition (LOGICOPERATOR condition)* SEPARATOR allocation (COMMA allocation)* 
      RIGHTPAREN (block|sentence) {System.out.println ("Entra en forloop");}; 

condition
    : condition_base (CONDITION condition_base)*;
condition_base
    : (LEFTPAREN)? exp (RIGHTPAREN)?;

block
  : LEFTBRACE {bloque++;} (sentence)* RIGHTBRACE {bloque--; System.out.println ("Entra en block");};

sentence
  : declarationc
  | ((allocation|functioncall) SEPARATOR)
  | specialfunctioncall
  | whileloop
  | ifblock
  | forloop
  | block {System.out.println ("Entra en sentence");};

